#include "message.h"
#include <string.h>
#include <iostream>

Message::Message()
{
	objList = new std::list<MapObject*>();
	clear();
}

int get_next_token(char* src, char* dst, int index)
{
	for(int i = 0; i + index < strlen(src); i++)
	{
		dst[i] = src[i + index];
		if(src[i + index] == ' ')
		{
			dst[i] = 0;
			return i + index + 1;
		}
		if(src[i + index] == ';')
		{
			dst[i + 1] = 0;
			return i + index + 1;
		}
	}
}

enum MsgState { MSG_TYPE = 0, MSG_TYPE_INIT = 1, MSG_TYPE_TELEMETRY = 2, MSG_TYPE_ACCIDENT = 3, MSG_TYPE_RESTART = 4, WAITING_END = 5, INIT_1 = 100, INIT_2 = 101, INIT_3 = 102, INIT_4 = 103, INIT_5 = 104, INIT_6 = 105, INIT_7 = 106, TELEMETRY_1 = 200, TELEMETRY_2 = 201, TELEMETRY_3 = 202, TELEMETRY_4 = 203, TELEMETRY_5 = 204, WAITING_OBJECT_OR_END = 205, STATIC_X = 206, STATIC_Y = 207, STATIC_R = 208, MARTIAN_X = 209, MARTIAN_Y = 210, MARTIAN_DIR = 211, MARTIAN_SPEED = 212, WAITING_SCORE = 400};

int Message::parse(char* msg)
{
	clear();
	char token[20];
	MsgState state = MSG_TYPE;
	int _int;
	double _dbl;
	char objKind;
	MapObject *ptr = 0;
	double static_x, static_y, static_radius, martian_x, martian_y, martian_dir, martian_speed;
	for(unsigned i = 0; i < strlen(msg);)
	{
		i = get_next_token(msg, token, i);
		switch(state)
		{
			case MSG_TYPE:
				if(token[0] == ';')
					return 1;
				if(strlen(token) != 1)
					return 14;
				mType = token[0];
				if(token[0] == 'I')
					state = MSG_TYPE_INIT;
				else if(token[0] == 'T')
					state = MSG_TYPE_TELEMETRY;
				else if((token[0] == 'B') || (token[0] == 'C') || (token[0] == 'K') || (token[0] == 'S'))
					state = MSG_TYPE_ACCIDENT;
				else if(token[0] == 'E')
					state = MSG_TYPE_RESTART;
				else
					return 2;
			break;
			case MSG_TYPE_ACCIDENT:
				_int = atoi(token);
				if(_int <= 0)
					return 3;
				timestamp = _int;
				state = WAITING_END;
			break;
			case WAITING_END:
				if(token[0] == ';')
					return 0;
			case MSG_TYPE_RESTART:
				_int = atoi(token);
				if(_int <= 0)
					return 4;
				timestamp = _int;
				state = WAITING_SCORE;
			break;
			case WAITING_SCORE:
				_int = atoi(token);
				if(_int <= 0)
					return 5;
				score = _int;
				state = WAITING_END;
			break;
			case MSG_TYPE_INIT:
				_dbl = atof(token);
				if(_dbl <= 0)
					return 6;
				mapX = _dbl;
				state = INIT_1;
			break;
			case INIT_1:
				_dbl = atof(token);
				if(_dbl <= 0)
					return 7;
				mapY = _dbl;
				state = INIT_2;
			break;
			case INIT_2:
				_int = atoi(token);
				if(_int <= 0)
					return 8;
				mapTimeLimit = _int;
				state = INIT_3;
			break;
			case INIT_3:
				_dbl = atof(token);
				if(_dbl <= 0)
					return 9;
				minSensor = _dbl;
				state = INIT_4;
			break;
			case INIT_4:
				_dbl = atof(token);
				if(_dbl < minSensor)
					return 10;
				maxSensor = _dbl;
				state = INIT_5;
			break;
			case INIT_5:
				_dbl = atof(token);
				if(_dbl <= 0)
					return 11;
				maxLinearSpeed = _dbl;
				state = INIT_6;
			break;
			case INIT_6:
				_dbl = atof(token);
				if(_dbl <= 0)
					return 12;
				maxTurnSpeed = _dbl;
				state = INIT_7;
			break;
			case INIT_7:
				_dbl = atof(token);
				if(_dbl <= 0)
					return 13;
				maxHardTurnSpeed = _dbl;
				state = WAITING_END;
			break;
			case MSG_TYPE_TELEMETRY:
				_int = atoi(token);
				if(_int < 0)
					return 15;
				timestamp = _int;
				state = TELEMETRY_1;
			break;
			case TELEMETRY_1:
				if(strlen(token) != 2)
					return 16;
				vehicleSpeedState = token[0];
				vehicleTurnState = token[1];
				state = TELEMETRY_2;
			break;
			case TELEMETRY_2:
				_dbl = atof(token); //trust that it is correct
				x = _dbl;
				state = TELEMETRY_3;
			break;
			case TELEMETRY_3:
				_dbl = atof(token); //trust that it is correct
				y = _dbl;
				state = TELEMETRY_4;
			break;
			case TELEMETRY_4:
				_dbl = atof(token); //trust that it is correct
				turn = _dbl;
				state = TELEMETRY_5;
			break;
			case TELEMETRY_5:
				_dbl = atof(token); //trust that it is correct
				speed = _dbl;
				state = WAITING_OBJECT_OR_END;
			break;
			case WAITING_OBJECT_OR_END:
				if(strlen(token) != 1)
					return 17;
				if(token[0] == ';')
					return 0;
				objKind = token[0];
				if(objKind == 'm')
					state = MARTIAN_X;
				else if((objKind == 'b') || (objKind == 'c') || (objKind == 'h'))
					state = STATIC_X;
				else
					return 18;
			break;
			case STATIC_X:
				_dbl = atof(token); //trust that it is correct
				static_x = _dbl;
				state = STATIC_Y;
			break;
			case STATIC_Y:
				_dbl = atof(token); //trust that it is correct
				static_y = _dbl;
				state = STATIC_R;
			break;
			case STATIC_R:
				_dbl = atof(token); //trust that it is correct
				static_radius = _dbl;
				if(objKind == 'b')	
					ptr = new Boulder(static_x, static_y, static_radius);
				if(objKind == 'c')
					ptr = new Crater(static_x, static_y, static_radius);
				if(objKind == 'h')
					ptr = new Home(static_x, static_y, static_radius);
				objList->push_back(ptr);
				state = WAITING_OBJECT_OR_END;
			break;
			case MARTIAN_X:
				_dbl = atof(token); //trust that it is correct
				martian_x = _dbl;
				state = MARTIAN_Y;
			break;
			case MARTIAN_Y:
				_dbl = atof(token); //trust that it is correct
				martian_y = _dbl;
				state = MARTIAN_DIR;
			break;
			case MARTIAN_DIR:
				_dbl = atof(token); //trust that it is correct
				martian_dir = _dbl;
				state = MARTIAN_SPEED;
			break;
			case MARTIAN_SPEED:
				_dbl = atof(token); //trust that it is correct
				martian_speed = _dbl;
				ptr = new Martian(martian_x, martian_y, martian_dir, martian_speed);
				objList->push_back(ptr); 
				state = WAITING_OBJECT_OR_END;
			break;
			default:
				return 19;
		}
	}
	return 20;
}

void Message::clear()
{
	mType = 0;

	mapX = 0, mapY = 0;
	mapTimeLimit = 0;
	minSensor = 0, maxSensor = 0;
	maxLinearSpeed = 0;
	maxTurnSpeed = 0;
	maxHardTurnSpeed = 0;
	
	timestamp = 0;
	score = 0;
	
	vehicleSpeedState = 0;
	vehicleTurnState = 0;
	x = 0, y = 0 ;
	turn = 0;
	speed = 0;
	objList->clear();

}

Message::~Message()
{
	delete objList;
}
